package com.zhike.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.green.model.v20180509.*;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.HttpResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.zhike.common.component.PrepareParams;
import com.zhike.common.dto.VideoDTO;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.util.*;

import org.springframework.stereotype.Component;

/**
 * 阿里云安全计策 1.文本 2.图片 3.音频 4.视频截祯
 *
 * @author zxd
 * @version 2024-11-22
 */
@Slf4j
@Component
public class AliSecurityCheckUtilsV1 {

    private static final String accessKeyId = "LTAI5tDiQc4QwnwrbD2LCjJE";
    private static final String accessKeySecret = "kSiuIfoHpWFRhOSCS9UDo79V7mf1xn";

    /**
     * 3.音频检测
     *
     * @param VoiceUrl
     * @return
     * @throws UnsupportedEncodingException
     */
    public Boolean checkVoice(String VoiceUrl) throws UnsupportedEncodingException {
        /**
         * 阿里云账号AccessKey拥有所有API的访问权限，建议您使用RAM用户进行API访问或日常运维。
         * 常见获取环境变量方式：
         * 方式一：
         * 获取RAM用户AccessKey ID：System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
         * 获取RAM用户AccessKey Secret：System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
         * 方式二：
         * 获取RAM用户AccessKey ID：System.getProperty("ALIBABA_CLOUD_ACCESS_KEY_ID");
         * 获取RAM用户AccessKey
         * Secret：System.getProperty("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
         */
        DefaultProfile profile = DefaultProfile.getProfile("cn-shanghai", accessKeyId, accessKeySecret);
        DefaultProfile.addEndpoint("cn-shanghai", "Green", "green.cn-shanghai.aliyuncs.com");
        // 注意：此处实例化的client尽可能重复使用，提升检测性能。避免重复建立连接。
        final IAcsClient client = new DefaultAcsClient(profile);

        VoiceSyncScanRequest syncScanRequest = new VoiceSyncScanRequest();
        syncScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        syncScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。
        syncScanRequest.setRegionId("cn-shanghai");
        syncScanRequest.setConnectTimeout(3000);
        syncScanRequest.setReadTimeout(6000);

        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        Map<String, Object> task1 = new LinkedHashMap<String, Object>();
        // 请将下面的地址修改为要检测的语音文件的地址。
        task1.put("url", VoiceUrl);
        tasks.add(task1);
        JSONObject data = new JSONObject();

        log.debug("==========Task count:{}", tasks.size());
        data.put("scenes", Arrays.asList("antispam"));
        data.put("tasks", tasks);
        syncScanRequest.setHttpContent(data.toJSONString().getBytes("UTF-8"), "UTF-8", FormatType.JSON);
        log.debug("{}", JSON.toJSONString(data, true));

        try {
            HttpResponse httpResponse = client.doAction(syncScanRequest);

            if (httpResponse.isSuccess()) {
                JSONObject scrResponse = JSON.parseObject(
                        org.apache.commons.codec.binary.StringUtils.newStringUtf8(httpResponse.getHttpContent()));
                log.debug("scrResponse: {}", JSON.toJSONString(scrResponse, true));
                int requestCode = scrResponse.getIntValue("code");
                JSONArray taskResults = scrResponse.getJSONArray("data");
                if (200 == requestCode) {
                    for (Object taskResult : taskResults) {
                        JSONArray sceneResults = ((JSONObject) taskResult).getJSONArray("results");
                        for (Object sceneResult : sceneResults) {
                            String scene = ((JSONObject) sceneResult).getString("scene");
                            String suggestion = ((JSONObject) sceneResult).getString("suggestion");
                            String label = ((JSONObject) sceneResult).getString("label");
                            // 根据scene和suggestion做相关处理。
                            // suggestion为pass表示未命中垃圾。suggestion为block表示命中了垃圾，可以通过label字段查看命中的垃圾分类。
                            log.debug("scene,args = [{}]", scene);
                            log.debug("suggestion,args = [{}]", suggestion);
                            if (suggestion.equals("pass") && label.equals("normal")) {
                                return true;
                            }
                        }
                    }
                } else {
                    log.error("detect not success. code: {}", scrResponse.getInteger("code"));
                }
            } else {
                log.error("response not success. status: {}", httpResponse.getStatus());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 4.视频检测
     *
     * @param VideoUrl
     * @return
     * @throws UnsupportedEncodingException
     */
    public Boolean checkVideo(PrepareParams pp) throws IOException {

        /**
         * 阿里云账号AccessKey拥有所有API的访问权限，建议您使用RAM用户进行API访问或日常运维。
         * 常见获取环境变量方式：
         * 方式一：
         * 获取RAM用户AccessKey ID：System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
         * 获取RAM用户AccessKey Secret：System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
         * 方式二：
         * 获取RAM用户AccessKey ID：System.getProperty("ALIBABA_CLOUD_ACCESS_KEY_ID");
         * 获取RAM用户AccessKey
         * Secret：System.getProperty("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
         */
        DefaultProfile profile = DefaultProfile.getProfile("cn-shanghai", accessKeyId, accessKeySecret);
        DefaultProfile.addEndpoint("cn-shanghai", "Green", "green.cn-shanghai.aliyuncs.com");
        // 注意：此处实例化的client尽可能重复使用，提升检测性能。避免重复建立连接。
        final IAcsClient client = new DefaultAcsClient(profile);

        VideoSyncScanRequest syncScanRequest = new VideoSyncScanRequest();
        syncScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        syncScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。
        syncScanRequest.setRegionId("cn-shanghai");
        syncScanRequest.setConnectTimeout(3000);
        syncScanRequest.setReadTimeout(6000);

        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        Map<String, Object> task1 = new LinkedHashMap<String, Object>();
        // 请将下面的地址修改为要检测的视频文件的地址。
        double time = getTime(pp.getVideoUrl());

        // task1.put("url", VideoUrl);
        task1.put("dataId", UUID.randomUUID().toString());

        List<VideoDTO> videoDTOS = new ArrayList<>();
        VideoDTO videoDTO = new VideoDTO();
        videoDTO.setUrl(pp.getApiServerUrl() + "/api/zkim/file/vframes?videoUrl=" + pp.getVideoUrl() + "&offset=" + 1);
        videoDTO.setOffset(1);

        VideoDTO videoDTO1 = new VideoDTO();
        videoDTO1
                .setUrl(pp.getApiServerUrl() + "/api/zkim/file/vframes?videoUrl=" + pp.getVideoUrl() + "&offset=" + 10);
        videoDTO1.setOffset(10);

        VideoDTO videoDTO2 = new VideoDTO();
        videoDTO2
                .setUrl(pp.getApiServerUrl() + "/api/zkim/file/vframes?videoUrl=" + pp.getVideoUrl() + "&offset=" + 18);
        videoDTO2.setOffset(18);

        VideoDTO videoDTO3 = new VideoDTO();
        videoDTO3
                .setUrl(pp.getApiServerUrl() + "/api/zkim/file/vframes?videoUrl=" + pp.getVideoUrl() + "&offset=" + 24);
        videoDTO3.setOffset(24);

        videoDTOS.add(videoDTO);
        if (time >= 10) {
            videoDTOS.add(videoDTO1);
        } else if (time >= 15) {
            videoDTOS.add(videoDTO2);
        } else if (time >= 24) {
            videoDTOS.add(videoDTO3);
        }
        task1.put("frames", videoDTOS);
        tasks.add(task1);
        JSONObject data = new JSONObject();

        log.debug("==========Task count: {}", tasks.size());
        data.put("scenes", Arrays.asList("porn", "live", "terrorism", "logo", "ad"));
        data.put("tasks", tasks);
        syncScanRequest.setHttpContent(data.toJSONString().getBytes("UTF-8"), "UTF-8", FormatType.JSON);
        log.debug("{}", JSON.toJSONString(data, true));

        try {
            HttpResponse httpResponse = client.doAction(syncScanRequest);
            if (httpResponse.isSuccess()) {
                JSONObject scrResponse = JSON.parseObject(
                        org.apache.commons.codec.binary.StringUtils.newStringUtf8(httpResponse.getHttpContent()));
                log.debug("{}", JSON.toJSONString(scrResponse, true));
                int requestCode = scrResponse.getIntValue("code");
                JSONArray taskResults = scrResponse.getJSONArray("data");

                if (200 == requestCode) {
                    for (Object taskResult : taskResults) {
                        JSONArray sceneResults = ((JSONObject) taskResult).getJSONArray("results");
                        for (Object sceneResult : sceneResults) {
                            String scene = ((JSONObject) sceneResult).getString("scene");
                            String suggestion = ((JSONObject) sceneResult).getString("suggestion");
                            // 根据scene和suggestion做相关处理。
                            // suggestion为pass表示未命中垃圾。suggestion为block表示命中了垃圾，可以通过label字段查看命中的垃圾分类。
                            log.debug("scene,args = [{}]", scene);
                            log.debug("suggestion,args = [{}]", suggestion);
                            if (suggestion.equals("pass")) {
                                return true;
                            }
                        }
                    }
                } else {
                    log.error("detect not success. code: {}", scrResponse.getInteger("code"));
                }
            } else {
                log.error("response not success. status: {}", httpResponse.getStatus());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * @return URL 所代表远程资源的响应结果
     */
    private double getTime(String videoUrl) {
        ProcessBuilder processBuilder = new ProcessBuilder(
                "ffprobe",
                "-v", "quiet",
                "-show_entries", "format=duration",
                "-of", "default=noprint_wrappers=1:nokey=1",
                videoUrl);

        // 启动进程
        Process process = null;
        try {
            process = processBuilder.start();

            // 读取输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String durationStr = reader.readLine();
            double duration = Double.parseDouble(durationStr);

            // 等待进程完成
            int exitCode = process.waitFor();

            if (exitCode == 0) {
                log.debug("视频时长: {}  秒", duration);
                return duration;
            } else {
                System.err.println("FFprobe 进程执行失败，退出码: " + exitCode);
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        return -1; // 返回-1表示获取失败
    }
}
